package _greedy

import org.junit.Assert
import org.junit.Test

/*
题型：贪心 / 动态规划
https://leetcode.cn/problems/jump-game/description/
https://programmercarl.com/0055.%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8F.html

55. 跳跃游戏

给你一个非负整数数组 nums ，你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标，如果可以，返回 true ；否则，返回 false 。

示例 1：
输入：nums = [2,3,1,1,4]
输出：true
解释：可以先跳 1 步，从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2：
输入：nums = [3,2,1,0,4]
输出：false
解释：无论怎样，总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 ， 所以永远不可能到达最后一个下标。
 */
class leetcode_55 {
    @Test
    fun test_1() {
        val actual = canJump(intArrayOf(2, 3, 1, 1, 4))
        val expect = true
        Assert.assertEquals(expect, actual)
    }

    @Test
    fun test_2() {
        val actual = canJump(intArrayOf(3, 2, 1, 0, 4))
        val expect = false
        Assert.assertEquals(expect, actual)
    }

    @Test
    fun test_143() {
        val actual = canJump(intArrayOf(0))
        val expect = true
        Assert.assertEquals(expect, actual)
    }

    fun canJump(nums: IntArray): Boolean {
        /*
        贪心算法
        核心思想：记录最远可达位置
        1 i 是人的位置
        2 覆盖范围超过最后一个数，说明跳到
         */
        // 很多贪心题目，都能用动态规划解决，此时动态规划空间优化后，就是贪心解法。
        var position: Int = 0

        for (i in 0 until nums.size) {
            // 判断无法继续前进
            if (i > position) {
                return false
            }

            // 更新index
            position = Math.max(position, i + nums[i])

            // 判断已经达到最后一个坐标
            if (position >= nums.size - 1) {
                return true
            }
        }
        return false
    }
}